package com.example.tms.service;

import com.example.tms.entity.Employee;
import com.example.tms.entity.EmployeeNode;
import com.example.tms.entity.Project;
import com.example.tms.entity.ProjectNode;
import com.example.tms.mapper.EmployeeMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.*;

@Service
public class GraphSyncService {
    private final Neo4jClient neo4jClient;
    private final EmployeeMapper employeeMapper;
    private final Neo4jTemplate neo4jTemplate;

    @Autowired // 添加构造器注解
    public GraphSyncService(Neo4jClient neo4jClient,
                            EmployeeMapper employeeMapper,
                            Neo4jTemplate neo4jTemplate) {
        this.neo4jClient = neo4jClient;
        this.employeeMapper = employeeMapper;
        this.neo4jTemplate = neo4jTemplate;
    }
    // 全量同步
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点同步
    public void fullSync() {
        neo4jClient.query("MATCH (n) DETACH DELETE n").run();
        syncAllEmployees();      // 同步所有员工数据
        syncManagerRelations();  // 同步上下级关系
        syncCollaborations();    // 同步协作关系
        syncColleagueRelations(); // 同事关系同步
    }

    // 同步所有基础员工数据
    @Transactional
    public void syncAllEmployees() {
        employeeMapper.selectList(null).forEach(emp -> {
            EmployeeNode node = neo4jTemplate.findById(emp.getId().toString(), EmployeeNode.class)
                    .orElseGet(() -> convertToNode(emp));
            neo4jTemplate.save(node);
        });
    }

    // 同步上下级关系
    public void syncManagerRelations() {
        neo4jClient.query("MATCH ()-[r:MANAGES]->() DELETE r").run();

        employeeMapper.findAllManagerRelations().forEach(rel -> {
            String employeeId = rel.getEmployeeId().toString();
            String managerId = rel.getManagerId().toString();

            EmployeeNode employee = neo4jTemplate.findById(employeeId, EmployeeNode.class)
                    .orElseThrow(() -> new RuntimeException("Employee not found: " + employeeId));

            EmployeeNode manager = neo4jTemplate.findById(managerId, EmployeeNode.class)
                    .orElseThrow(() -> new RuntimeException("Manager not found: " + managerId));

            // 建立管理关系
            if (manager.getSubordinates() == null) {
                manager.setSubordinates(new ArrayList<>());
            }
            manager.getSubordinates().add(employee);
            neo4jTemplate.save(manager);
        });
    }

    // 同步同事关系
    public void syncColleagueRelations() {
        neo4jClient.query("MATCH ()-[r:COLLEAGUE]->() DELETE r").run();

        employeeMapper.findAllColleagueRelations().forEach(rel -> {
            String emp1Id = rel.get("employee1").toString();
            String emp2Id = rel.get("employee2").toString();
            String departmentId = rel.get("departmentId").toString();

            EmployeeNode emp1 = neo4jTemplate.findById(emp1Id, EmployeeNode.class)
                    .orElseGet(() -> createBasicEmployeeNode(emp1Id));

            EmployeeNode emp2 = neo4jTemplate.findById(emp2Id, EmployeeNode.class)
                    .orElseGet(() -> createBasicEmployeeNode(emp2Id));

            // 在关系上添加部门ID属性
            neo4jClient.query("""
            MATCH (e1:Employee {id: $emp1Id}), (e2:Employee {id: $emp2Id})
            MERGE (e1)-[r:COLLEAGUE {department: $departmentId}]-(e2)
            """)
                    .bind(emp1Id).to("emp1Id")
                    .bind(emp2Id).to("emp2Id")
                    .bind(departmentId).to("departmentId")
                    .run();
        });
    }

    // 同步协作关系
    public void syncCollaborations() {
        employeeMapper.findAllCollaborations().forEach(collab -> {
            neo4jClient.query("MATCH ()-[r:COLLEAGUE]->() DELETE r").run();
            String emp1Id = collab.get("employee1").toString();
            String emp2Id = collab.get("employee2").toString();
            String projectId = collab.get("projectId").toString();
            // 创建项目节点(使用实际项目ID)
            ProjectNode project = new ProjectNode();
            project.setId(projectId); // 直接使用MySQL的项目ID
            neo4jTemplate.save(project);
            EmployeeNode emp1 = neo4jTemplate.findById(emp1Id, EmployeeNode.class)
                    .orElseGet(() -> createBasicEmployeeNode(emp1Id));

            EmployeeNode emp2 = neo4jTemplate.findById(emp2Id, EmployeeNode.class)
                    .orElseGet(() -> createBasicEmployeeNode(emp2Id));

            // 双向建立协作关系（带项目名称属性）
            if (emp1.getColleagues() == null) {
                emp1.setColleagues(new HashSet<>());
            }
            if (emp2.getColleagues() == null) {
                emp2.setColleagues(new HashSet<>());
            }
            emp1.getColleagues().add(emp2);
            emp2.getColleagues().add(emp1);

            neo4jTemplate.save(emp1);
            neo4jTemplate.save(emp2);

            if (emp1.getProjects() == null) {
                emp1.setProjects(new HashSet<>());
            }
            if (emp2.getProjects() == null) {
                emp2.setProjects(new HashSet<>());
            }
            emp1.getProjects().add(project);
            emp2.getProjects().add(project);

            neo4jTemplate.save(emp1);
            neo4jTemplate.save(emp2);
        });
    }

    // 创建基础员工节点
    public EmployeeNode createBasicEmployeeNode(String empId) {
        Integer mysqlId = Integer.valueOf(empId);
        Employee employee = employeeMapper.selectById(mysqlId);
//        Employee employee = employeeMapper.selectById(empId);
        EmployeeNode node = new EmployeeNode();
        node.setId(empId);
        node.setName(employee != null ? employee.getName() : "Unknown");
        return node;
    }

    public EmployeeNode convertToNode(Employee employee) {
        EmployeeNode node = new EmployeeNode();
        node.setId(employee.getId().toString());
        node.setName(employee.getName());
        return node;
    }

    public ProjectNode convertProjectToNode(Project project) {
        ProjectNode node = new ProjectNode();
        node.setId(project.getId().toString());
        node.setName(project.getName());
        return node;
    }

    // 增量添加项目参与
    @Transactional
    public void addProjectParticipation(String empId, String projectId) {
        // MySQL操作
        employeeMapper.insertProjectParticipation(Integer.valueOf(empId), Integer.valueOf(projectId));
        // Neo4j操作
        EmployeeNode employee = neo4jTemplate.findById(empId, EmployeeNode.class)
                .orElseGet(() -> createBasicEmployeeNode(empId));  // 直接传Integer

        ProjectNode project = neo4jTemplate.findById(projectId, ProjectNode.class)
                .orElseThrow(() -> new RuntimeException("Project not found"));

        employee.getProjects().add(project);
        neo4jTemplate.save(employee);

        createColleagueRelations(projectId.toString());
    }

    @Transactional
    public void createColleagueRelations(String projectId) {
        neo4jClient.query("""
            MATCH (e1:Employee)-[:PARTICIPATED_IN]->(p:Project {id: $projectId})
            MATCH (e2:Employee)-[:PARTICIPATED_IN]->(p)
            WHERE e1 <> e2
            MERGE (e1)-[:COLLEAGUE {project: p.name}]-(e2)
            """)
                .bind(projectId).to("projectId")
                .run();
    }

    // 添加可视化查询方法
    public Map<String, Object> visualizeRelations(String employeeId) {
        return neo4jClient.query("""
        MATCH (e:Employee {id: $id})
        OPTIONAL MATCH (e)-[r1:MANAGES]->(sub)
        OPTIONAL MATCH (e)<-[r2:MANAGES]-(mgr)
        OPTIONAL MATCH (e)-[r3:COLLEAGUE]-(col)
        RETURN {
            center: properties(e),
            managers: COLLECT(DISTINCT properties(mgr)),
            subordinates: COLLECT(DISTINCT properties(sub)),
            colleagues: COLLECT(DISTINCT {
                colleague: properties(col), 
                projects: r3.project
            })
        } as graph
        """)
                .bind(employeeId).to("id")
                .fetchAs(Map.class)
                .one()
                .orElse(Collections.emptyMap());
    }

}
